import os, bpy, bpy.ops, math, mathutils, ossl.util as util, bmesh
from mathutils import Vector, Euler
from rna_xml import rna2xml
import xml.etree.ElementTree as ET
from bpy.types import Operator
from ossl.util import fmt
from math import pi

PRINT_LSL_LIST = True
CREATE_WINDOWS = False

def center(min, max):
    return min + (max - min) / 2.0

class BBox:
    def __init__(self, cutter):
        self.cutter = cutter
        xmin = 999999.0; xmax = -999999.0
        ymin = 999999.0; ymax = -999999.0
        zmin = 999999.0; zmax = -999999.0
        for p in cutter.bound_box:
            v = cutter.matrix_world @ Vector(p)
            if (v.x < xmin): xmin = v.x
            if (v.y < ymin): ymin = v.y
            if (v.z < zmin): zmin = v.z
            if (v.x > xmax): xmax = v.x
            if (v.y > ymax): ymax = v.y
            if (v.z > zmax): zmax = v.z
        self.min = Vector((xmin, ymin, zmin))
        self.max = Vector((xmax, ymax, zmax))
        self.loc = center(self.min, self.max)
        # if (cutter.name == "WindowCutter top"): print(":::: " + fmt(self.loc) + ", min=" + fmt(self.min) + ", max=" + fmt(self.max))
        self.wloc = Vector((0,0,0))

    def contains(self, v):
        if (v.x < self.min.x): return False
        if (v.y < self.min.y): return False
        if (v.z < self.min.z): return False
        if (v.x > self.max.x): return False
        if (v.y > self.max.y): return False
        if (v.z > self.max.z): return False
        return True
    
    def expand(self, d):
        self.min -= Vector((d, d, d))
        self.max += Vector((d, d, d))

    def shrink(self, d):
        self.min += Vector((d, d, d))
        self.max -= Vector((d, d, d))

def analyze_saloon_windows():
    context = bpy.context
    scene = context.scene
 
    util.setMode("OBJECT")

    def select(ob):
        for o in scene.objects:
            if (o.select_get()): o.select_set(False)
        context.view_layer.objects.active = None
        ob.select_set(True)
        context.view_layer.objects.active = ob

    walls = bpy.context.scene.objects["Walls"]
    select(walls)

    wb = BBox(walls)
    wb.shrink(0.7)
    #print(walls.name, str(len(walls.data.vertices)), "vertices, min="+fmt(wb.min)+", max="+fmt(wb.max))
    #print()

    xm = []; xp = []; ym = []; yp = []
    for v in walls.data.vertices:
        v = walls.matrix_world @ v.co
        if v.x < wb.min.x: xm.append(v)
        if v.x > wb.max.x: xp.append(v)
        if v.y < wb.min.y: ym.append(v)
        if v.y > wb.max.y: yp.append(v)
    #print("n xm", len(xm))
    #print("n xp", len(xp))
    #print("n ym", len(ym))
    #print("n yp", len(yp))
    #print()

    cxm = []; cxp = []; cym = []; cyp = []
    refCutter = None; refBox = None
    for o in bpy.context.scene.objects:
        if (o.name.startswith("WindowCutter ")):
            b = BBox(o)
            b.expand(0.01)
            #print(b.cutter.name + ", min=" + fmt(b.min) + ", max=" + fmt(b.max) + ", loc=" + fmt(b.loc))
            if (b.min.x < wb.min.x): cxm.append(b)
            if (b.max.x > wb.max.x): cxp.append(b)
            if (b.min.y < wb.min.y): cym.append(b)
            if (b.max.y > wb.max.y): cyp.append(b)
            if (o.name == "WindowCutter top"):
                refCutter = o
                refBox = b

    #print("n cxm", len(cxm))
    #print("n cxp", len(cxp))
    #print("n cym", len(cym))
    #print("n cyp", len(cyp))
    #print()
    #print("refCutter:", refCutter)
    #print()

    cxmp = []; cxpp = []; cymp = []; cypp = []

    def findLocIn(cb, vc, r):
        vv = []
        for v in vc:
            if cb.contains(v):
                vv.append(v)
                #if (cb.cutter.name == "WindowCutter top"): print("→→→ " + fmt(v))

        xmin = 999999.0; xmax = -999999.0
        ymin = 999999.0; ymax = -999999.0
        zmin = 999999.0; zmax = -999999.0
        for v in vv:
            if (v.x < xmin): xmin = v.x
            if (v.y < ymin): ymin = v.y
            if (v.z < zmin): zmin = v.z
            if (v.x > xmax): xmax = v.x
            if (v.y > ymax): ymax = v.y
            if (v.z > zmax): zmax = v.z
        min = Vector((xmin, ymin, zmin))
        max = Vector((xmax, ymax, zmax))
        loc = center(min, max)
        cb.wloc = loc
        #if ((cb.cutter.name == "WindowCutter top") or (cb.cutter.name == "WindowCutter top.001")):
        #    print("→→→ " + cb.cutter.name + "→→→ " + fmt(loc))
        return (cb, loc, r)

    for cb in cxm: cxmp.append(findLocIn(cb, xm, 2))
    for cb in cxp: cxpp.append(findLocIn(cb, xp, 0))
    for cb in cym: cymp.append(findLocIn(cb, ym, 1))
    for cb in cyp: cypp.append(findLocIn(cb, yp, 3))

    # print("cxmp"); for vv in cxmp: print(fmt(vv))
    # print("cxpp"); for vv in cxpp: print(fmt(vv))
    # print("cymp"): for vv in cymp: print(fmt(vv))
    # print("cypp"): for vv in cypp: print(fmt(vv))

    bb = BBox(bpy.data.objects["Windowframe"])
    #print("Windowframe loc=" + fmt(bb.loc))

    pnts = []

    def wf(b, r):
        p = b.wloc # - refBox.wloc
        pnts.append((p, r))
        p = p - refBox.wloc
        n = b.cutter.name[13:14]
        if (b.cutter.name[-4] != "."): n += "00"
        else: n += b.cutter.name[-2:]
        print("\t\"" + n + "\", " + str(r) + ", <" + fmt(p.x) + ", " + fmt(p.y) + ", " + fmt(p.z) + ">,")

    if (PRINT_LSL_LIST):
        print()
        print("list L = [ ")
        for p in cxpp: wf(p[0], 0)
        for p in cymp: wf(p[0], 1)
        for p in cxmp: wf(p[0], 2)
        for p in cypp: wf(p[0], 3)
        print("-1 ];")

    if (CREATE_WINDOWS):
        for pp in pnts:
            p = pp[0] # + refBox.loc
            frame = scene.objects["Windowframe"]
            select(frame)
            bpy.ops.object.duplicate(False)
            frame = bpy.context.view_layer.objects.active
            select(frame)
            frame.rotation_euler[2] = pi/2.0 * (pp[1]-2)
            frame.location = p
